package com.ruoyi.web.controller.sso;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.domain.SysSsoLog;
import com.ruoyi.system.domain.SysSsoSystem;
import com.ruoyi.system.domain.vo.SsoUserVo;
import com.ruoyi.system.service.SsoService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @author wangyan
 * 单点登录及验证
 */
@RequestMapping("/sso/webapp")
@Slf4j
@RestController
public class SsoController {

//    private static final Logger log = LoggerFactory.getLogger(SsoController.class);

    @Autowired
    private SsoService ssoService;

    @Resource
    private TokenService tokenService;

    @RequestMapping("/token")
    @ApiOperation(value = "获取加密token", notes = "获取加密token")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "secretkey", value = "系统密钥（各系统不同）", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "appurl", value = "应用系统回调地址", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "appid", value = "应用编码", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "method", value = "HttpGet/HttpPost,默认使用HttpGet", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "timeout", value = "请求超时时间", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "logouturl", value = "执行统一注销，可选", dataType = "String", paramType = "query")
    })
    @ResponseBody
    public void getToken(HttpServletResponse response,
                         HttpServletRequest request,
                         @RequestParam(required = true) String secretkey,
                         @RequestParam(required = true) String appurl,
                         @RequestParam(required = true) String appid,
                         @RequestParam(required = false) String method,
                         @RequestParam(required = false) Integer timeout,
                         @RequestParam(required = false) String logouturl) {
        String url;
        StringBuffer stringBuffer = null;
        try {
            //校验系统
            SysSsoSystem ssoSystem = ssoService.findByScAndCode(secretkey, appid);
            if (ssoSystem == null) {
                log.info("校验失败1..");
                response.sendRedirect(request.getScheme() + "://" + request.getServerName());
                return;
            }
            String token = request.getHeader("Authorization");
            //AuthUtils
            if(StringUtils.isBlank(token)){
                log.info("校验失败2..");
                response.sendRedirect(request.getScheme() + "://" + request.getServerName());
                return;
            }else{
                token=token.replaceAll("Bearer ","");
            }
            SysSsoLog ssoLog = null;
            LoginUser loginUser = SecurityUtils.getLoginUser();
            if (loginUser != null) {
                SysUser user = loginUser.getUser();
                if (user != null) {
                    //添加SSO日志
                    ssoLog = new SysSsoLog();
                    ssoLog.setSysCode(appid);
                    ssoLog.setSysLogintime(new Date());
                    ssoLog.setSysLoginuser(user.getNickName());
                    ssoService.insertLog(ssoLog);
                }else{
                    log.info("校验失败,未登陆...");
                    response.sendRedirect(request.getScheme() + "://" + request.getServerName());
                    return;
                }
            }else{
                log.info("校验失败3..");
                response.sendRedirect(request.getScheme() + "://" + request.getServerName());
                return;
            }

            //登出地址不为空记录登出路径
            if (!StringUtils.isEmpty(logouturl)) {
                ssoSystem.setSysLogouturl(logouturl);
                ssoService.updateSsoLogOut(ssoSystem);
            }
            String ssoUrl=appurl;
            log.info("开始跳转..."+ssoUrl+"?token="+token);
            ssoUrl=ssoUrl+"?token="+token;
            response.sendRedirect(ssoUrl);
        } catch (IOException e) {
            log.error("\n调用webapi接口【getToken()】 ", e.getMessage());
        }
    }

    @PostMapping("/dectoken")
    @ApiOperation(value = "解密加密token", notes = "解密加密token")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "secretkey", value = "系统密钥（各系统不同）", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "appid", value = "应用编码", dataType = "String", paramType = "query")
    })
    @ResponseBody
    public Map<String, Object> decToken(@RequestParam(required = true) String secretkey,
                                        @RequestParam(required = true) String appid) {
        //校验系统
        SysSsoSystem ssoSystem = ssoService.findByScAndCode(secretkey, appid);
        Map<String, Object> map = new ConcurrentHashMap<>();
        if (ssoSystem == null) {
            Map<String, Object> mapTemplate = new ConcurrentHashMap<>();
            mapTemplate.put("code", -1);
            mapTemplate.put("msg", "系统校验失败,密钥或ID错误");
            mapTemplate.put("data", null);
            return mapTemplate;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SsoUserVo ssoUserVo = null;
        SysSsoLog ssoLog = null;
        try {
            if (loginUser != null) {
                SysUser user = loginUser.getUser();
                ssoUserVo = new SsoUserVo();
                ssoUserVo.setAppid(appid);
                ssoUserVo.setAsid(java.util.UUID.randomUUID().toString());
                ssoUserVo.setSigntime(sdf.format(new Date()));
                ssoUserVo.setUid(user.getUserId().toString());
                ssoUserVo.setUname(user.getNickName());
                //添加SSO日志
                ssoLog = new SysSsoLog();
                ssoLog.setId(java.util.UUID.randomUUID().toString());
                ssoLog.setSysCode(appid);
                ssoLog.setSysLogintime(new Date());
                ssoLog.setSysLoginuser(user.getNickName());
                ssoService.insertLog(ssoLog);
            }
            map.put("code", 0);
            map.put("msg", "用户信息解析成功");
            map.put("data", ssoUserVo);
        } catch (Exception e) {
            log.error("\n调用webapi接口【dectoken()】 ", e.getMessage());
        }
        return map;
    }

    @PostMapping("/decipherToken")
    @ApiOperation(value = "解密token", notes = "解密token")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "token", value = "系统密钥（各系统不同）", dataType = "String", paramType = "query",required = true)
    })
    @ResponseBody
    public Map<String, Object> decipherToken(@RequestParam(required = true) String token) {
        log.info("调用token解密接口 : {}",token);
        Map<String, Object> map = new ConcurrentHashMap<>(4);
        /**
         * 正式逻辑--开始
         */
        LoginUser userFromToken = tokenService.getUserFromToken(token);
        if (userFromToken==null){
            map.put("code", -1);
            map.put("msg", "用户已失效");
            return map;
        }
        SysUser loginUser = userFromToken.getUser();
        log.info("解析token，token的所有者为：  {} , userNo为 ： {}",loginUser.getNickName(),loginUser.getUserNo());
        SysSsoLog ssoLog = null;
        try {
            SsoUserVo ssoUserVo = new SsoUserVo();
            ssoUserVo.setUid(loginUser.getUserNo());
            ssoUserVo.setUname(loginUser.getNickName());
            map.put("code", 0);
            map.put("msg", "用户信息解析成功");
            map.put("data", ssoUserVo);

            ssoLog = new SysSsoLog();
            ssoLog.setId(java.util.UUID.randomUUID().toString());
            ssoLog.setSysLogintime(new Date());
            ssoLog.setSysLoginuser(loginUser.getNickName());
            ssoService.insertLog(ssoLog);
        } catch (Exception e) {
            log.error("调用webapi接口decipherToken()失败： {}", e.getMessage());
        }
        /**
         * 正式逻辑--结束
         */
        return map;
    }


    @GetMapping("/ssologout")
    @ApiOperation(value = "sso登出", notes = "sso登出,返回所有需要注销的系统的注销地址，均为HttpGet，前端统一调用")
    @ResponseBody
    public AjaxResult ssoLogOut(HttpServletResponse response, HttpServletRequest request) {
        List<String> list = new ArrayList<>();
        try {
            List<SysSsoSystem> ssoSystems = ssoService.selectAll();
            for (SysSsoSystem ssoSystem : ssoSystems) {
                if (StringUtils.isEmpty(ssoSystem.getSysLogouturl())) {
                    list.add(ssoSystem.getSysLogouturl());
                }
            }
        } catch (Exception e) {
            log.error("\n调用webapi接口【ssoLogOut()】 ", e.getMessage());
        }
        return AjaxResult.success("get data success.", list);
    }

}
